﻿// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com

// ReSharper disable CheckNamespace
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable CommentTypo
// ReSharper disable IdentifierTypo
// ReSharper disable InconsistentNaming
// ReSharper disable StringLiteralTypo
// ReSharper disable UnusedParameter.Local

/*
 * Ars Magna project, http://arsmagna.ru
 */

#region Using directives

using System;
using System.Collections.Generic;

#endregion

#nullable enable

namespace AM.Memory.Collections.Specialized;

/// <summary>
/// Contains 8 elements as struct fields as Maximum. Use it when you have guaranteed count of elements &#8804; 8
/// </summary>
public struct LongLocalList<T>
{
    private static readonly EqualityComparer<T> ItemComparer = EqualityComparer<T>.Default;

    private (T, T, T, T, T, T, T, T) _items;

    /// <summary>
    ///
    /// </summary>
    public const int Capacity = 8;

    /// <summary>
    ///
    /// </summary>
    /// <param name="item"></param>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public void Add (T item)
    {
        Count++;
        if (Count >= Capacity) throw new ArgumentOutOfRangeException();

        this[Count - 1] = item;
    }

    /// <summary>
    ///
    /// </summary>
    public void Clear()
    {
        Count = 0;
        _items = default;
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="item"></param>
    /// <returns></returns>
    public bool Contains (T item)
    {
        return IndexOf (item) >= 0;
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="array"></param>
    /// <param name="arrayIndex"></param>
    public void CopyTo (T[] array, int arrayIndex)
    {
        for (var i = 0; i < Capacity; i++) array[i] = this[i];
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="item"></param>
    /// <returns></returns>
    public bool Remove (T item)
    {
        var i = 0;
        var j = 0;

        for (; i < Capacity; i++)
        {
            if (ItemComparer.Equals (this[i], item) != true) j++;
            else continue;
            this[j] = this[i];
        }

        return j != i;
    }

    /// <summary>
    ///
    /// </summary>
    public int Count { get; private set; }

    /// <summary>
    ///
    /// </summary>
    public bool IsReadOnly => false;

    /// <summary>
    ///
    /// </summary>
    /// <param name="item"></param>
    /// <returns></returns>
    public int IndexOf (T item)
    {
        for (var i = 0; i < Capacity; i++)
            if (ItemComparer.Equals (this[i], item))
                return i;
        return -1;
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="index"></param>
    /// <exception cref="IndexOutOfRangeException"></exception>
    public T this [int index]
    {
        get
        {
            if (index < 0 || index >= Count)
                throw new IndexOutOfRangeException();

            switch (index)
            {
                case 0: return _items.Item1;
                case 1: return _items.Item2;
                case 2: return _items.Item3;
                case 3: return _items.Item4;
                case 4: return _items.Item5;
                case 5: return _items.Item6;
                case 6: return _items.Item7;
                case 7: return _items.Item8;
                default: throw new IndexOutOfRangeException();
            }
        }
        set
        {
            if (index < 0 || index >= Count)
                throw new IndexOutOfRangeException();

            switch (index)
            {
                case 0:
                    _items.Item1 = value;
                    break;
                case 1:
                    _items.Item2 = value;
                    break;
                case 2:
                    _items.Item3 = value;
                    break;
                case 3:
                    _items.Item4 = value;
                    break;
                case 4:
                    _items.Item5 = value;
                    break;
                case 5:
                    _items.Item6 = value;
                    break;
                case 6:
                    _items.Item7 = value;
                    break;
                case 7:
                    _items.Item8 = value;
                    break;
                default: throw new IndexOutOfRangeException();
            }
        }
    }

    /// <inheritdoc cref="ValueType.GetHashCode"/>
    public override int GetHashCode()
    {
        return _items.GetHashCode();
    }

    /// <inheritdoc cref="ValueType.Equals(object?)"/>
    public override bool Equals (object? obj)
    {
        return obj is LongLocalList<T> other && Equals (other);
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="other"></param>
    /// <returns></returns>
    public bool Equals (LongLocalList<T> other)
    {
        return _items.Equals (other._items);
    }
}
